package com.aspire.aimini.service.impl;

import com.aspire.aimini.model.entity.ExportTask;
import com.aspire.aimini.repository.*;
import com.aspire.aimini.service.ExportService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * 导出服务实现类
 *
 * @author wangguiyou
 * @date 2024-12-19
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ExportServiceImpl implements ExportService {

    private final ExportTaskRepository exportTaskRepository;
    private final MaterialRepository materialRepository;
    private final TagRepository tagRepository;
    private final CopywritingRepository copywritingRepository;
    private final UserRepository userRepository;
    private final GenerationRecordRepository generationRecordRepository;

    /**
     * 创建导出任务
     *
     * @param userId   用户ID
     * @param dataType 数据类型
     * @param format   导出格式
     * @param filters  过滤条件
     * @return 导出任务ID
     */
    @Override
    @Transactional
    public Long createExportTask(Long userId, String dataType, String format, Map<String, Object> filters) {
        log.info("创建导出任务: userId={}, dataType={}, format={}", userId, dataType, format);

        ExportTask task = new ExportTask();
        task.setUserId(userId);
        task.setDataType(dataType);
        task.setFormat(format);
        task.setFilters(filters != null ? filters.toString() : null);
        task.setStatus("PENDING");
        task.setPriority(5); // 默认优先级
        task.setCreatedAt(LocalDateTime.now());
        task.setUpdatedAt(LocalDateTime.now());

        // 估算文件大小
        long estimatedSize = estimateExportFileSize(dataType, filters);
        task.setEstimatedSize(estimatedSize);

        ExportTask savedTask = exportTaskRepository.save(task);

        // 异步执行导出任务
        executeExportTaskAsync(savedTask.getId());

        return savedTask.getId();
    }

    /**
     * 查询导出任务
     *
     * @param taskId 任务ID
     * @return 导出任务
     */
    @Override
    public ExportTask getExportTask(Long taskId) {
        log.info("查询导出任务: taskId={}", taskId);

        return exportTaskRepository.findById(taskId)
                .orElseThrow(() -> new RuntimeException("导出任务不存在: " + taskId));
    }

    /**
     * 获取导出任务下载链接
     *
     * @param taskId 任务ID
     * @return 下载链接
     */
    @Override
    public String getExportTaskDownloadUrl(Long taskId) {
        log.info("获取导出任务下载链接: taskId={}", taskId);

        ExportTask task = getExportTask(taskId);

        if (!"COMPLETED".equals(task.getStatus())) {
            throw new RuntimeException("导出任务未完成，无法下载");
        }

        if (task.getFilePath() == null) {
            throw new RuntimeException("导出文件不存在");
        }

        // 生成临时下载链接
        String downloadUrl = generateDownloadUrl(task.getFilePath());

        // 更新下载次数
        task.setDownloadCount(task.getDownloadCount() + 1);
        task.setLastDownloadAt(LocalDateTime.now());
        exportTaskRepository.save(task);

        return downloadUrl;
    }

    /**
     * 取消导出任务
     *
     * @param taskId 任务ID
     */
    @Override
    @Transactional
    public void cancelExportTask(Long taskId) {
        log.info("取消导出任务: taskId={}", taskId);

        ExportTask task = getExportTask(taskId);

        if ("COMPLETED".equals(task.getStatus()) || "CANCELLED".equals(task.getStatus())) {
            throw new RuntimeException("任务已完成或已取消，无法取消");
        }

        task.setStatus("CANCELLED");
        task.setUpdatedAt(LocalDateTime.now());
        exportTaskRepository.save(task);
    }

    /**
     * 删除导出任务
     *
     * @param taskId 任务ID
     */
    @Override
    @Transactional
    public void deleteExportTask(Long taskId) {
        log.info("删除导出任务: taskId={}", taskId);

        ExportTask task = getExportTask(taskId);

        // 删除导出文件
        if (task.getFilePath() != null) {
            deleteExportFile(task.getFilePath());
        }

        exportTaskRepository.deleteById(taskId);
    }

    /**
     * 获取用户导出任务列表
     *
     * @param userId   用户ID
     * @param pageable 分页参数
     * @return 导出任务列表
     */
    @Override
    public Page<ExportTask> getUserExportTasks(Long userId, Pageable pageable) {
        log.info("获取用户导出任务列表: userId={}", userId);

        return exportTaskRepository.findByUserIdOrderByCreatedAtDesc(userId, pageable);
    }

    /**
     * 导出素材数据
     *
     * @param userId  用户ID
     * @param format  导出格式
     * @param filters 过滤条件
     * @return 导出任务ID
     */
    @Override
    public Long exportMaterials(Long userId, String format, Map<String, Object> filters) {
        log.info("导出素材数据: userId={}, format={}", userId, format);

        return createExportTask(userId, "MATERIAL", format, filters);
    }

    /**
     * 导出文案数据
     *
     * @param userId  用户ID
     * @param format  导出格式
     * @param filters 过滤条件
     * @return 导出任务ID
     */
    @Override
    public Long exportCopywritings(Long userId, String format, Map<String, Object> filters) {
        log.info("导出文案数据: userId={}, format={}", userId, format);

        return createExportTask(userId, "COPYWRITING", format, filters);
    }

    /**
     * 导出标签数据
     *
     * @param userId  用户ID
     * @param format  导出格式
     * @param filters 过滤条件
     * @return 导出任务ID
     */
    @Override
    public Long exportTags(Long userId, String format, Map<String, Object> filters) {
        log.info("导出标签数据: userId={}, format={}", userId, format);

        return createExportTask(userId, "TAG", format, filters);
    }

    /**
     * 导出统计数据
     *
     * @param userId         用户ID
     * @param format         导出格式
     * @param statisticsType 统计类型
     * @param filters        过滤条件
     * @return 导出任务ID
     */
    @Override
    public Long exportStatistics(Long userId, String format, String statisticsType, Map<String, Object> filters) {
        log.info("导出统计数据: userId={}, format={}, statisticsType={}", userId, format, statisticsType);

        Map<String, Object> exportFilters = new HashMap<>();
        if (filters != null) {
            exportFilters.putAll(filters);
        }
        exportFilters.put("statisticsType", statisticsType);

        return createExportTask(userId, "STATISTICS", format, exportFilters);
    }

    /**
     * 导出用户数据
     *
     * @param userId              用户ID
     * @param format              导出格式
     * @param includePersonalData 是否包含个人数据
     * @return 导出任务ID
     */
    @Override
    public Long exportUserData(Long userId, String format, boolean includePersonalData) {
        log.info("导出用户数据: userId={}, format={}, includePersonalData={}", userId, format, includePersonalData);

        Map<String, Object> filters = new HashMap<>();
        filters.put("includePersonalData", includePersonalData);

        return createExportTask(userId, "USER_DATA", format, filters);
    }

    /**
     * 批量导出
     *
     * @param userId         用户ID
     * @param exportRequests 导出请求列表
     * @return 导出任务ID列表
     */
    @Override
    public List<Long> batchExport(Long userId, List<Map<String, Object>> exportRequests) {
        log.info("批量导出: userId={}, requestCount={}", userId, exportRequests.size());

        List<Long> taskIds = new ArrayList<>();

        for (Map<String, Object> request : exportRequests) {
            String dataType = (String) request.get("dataType");
            String format = (String) request.get("format");
            @SuppressWarnings("unchecked")
            Map<String, Object> filters = (Map<String, Object>) request.get("filters");

            Long taskId = createExportTask(userId, dataType, format, filters);
            taskIds.add(taskId);
        }

        return taskIds;
    }

    /**
     * 获取支持的导出格式
     *
     * @return 支持的导出格式列表
     */
    @Override
    public List<String> getSupportedExportFormats() {
        log.info("获取支持的导出格式");

        return Arrays.asList("CSV", "EXCEL", "JSON", "XML", "PDF");
    }

    /**
     * 获取导出模板
     *
     * @param dataType 数据类型
     * @return 导出模板列表
     */
    @Override
    public List<Map<String, Object>> getExportTemplates(String dataType) {
        log.info("获取导出模板: dataType={}", dataType);

        List<Map<String, Object>> templates = new ArrayList<>();

        switch (dataType.toUpperCase()) {
            case "MATERIAL":
                templates.add(createTemplate("基础模板", "包含基本素材信息",
                        Arrays.asList("id", "title", "fileType", "fileSize", "createdAt")));
                templates.add(createTemplate("详细模板", "包含完整素材信息", Arrays.asList("id", "title", "description", "fileType",
                        "fileSize", "tags", "viewCount", "downloadCount", "createdAt", "updatedAt")));
                break;
            case "COPYWRITING":
                templates.add(createTemplate("基础模板", "包含基本文案信息",
                        Arrays.asList("id", "title", "content", "contentType", "createdAt")));
                templates.add(createTemplate("详细模板", "包含完整文案信息", Arrays.asList("id", "title", "content", "contentType",
                        "style", "aiModel", "usageCount", "createdAt", "updatedAt")));
                break;
            case "TAG":
                templates
                        .add(createTemplate("基础模板", "包含基本标签信息", Arrays.asList("id", "name", "category", "usageCount")));
                templates.add(createTemplate("详细模板", "包含完整标签信息", Arrays.asList("id", "name", "category", "description",
                        "isSystem", "usageCount", "createdAt", "updatedAt")));
                break;
            default:
                templates.add(createTemplate("默认模板", "默认导出模板", Arrays.asList("id", "name", "createdAt")));
        }

        return templates;
    }

    /**
     * 预览导出内容
     *
     * @param dataType 数据类型
     * @param format   导出格式
     * @param filters  过滤条件
     * @param limit    预览数量限制
     * @return 预览内容
     */
    @Override
    public Map<String, Object> previewExportContent(String dataType, String format, Map<String, Object> filters,
            int limit) {
        log.info("预览导出内容: dataType={}, format={}, limit={}", dataType, format, limit);

        Map<String, Object> preview = new HashMap<>();
        preview.put("dataType", dataType);
        preview.put("format", format);
        preview.put("limit", limit);

        // 根据数据类型获取预览数据
        List<Map<String, Object>> previewData = getPreviewData(dataType, filters, limit);
        preview.put("data", previewData);
        preview.put("totalCount", getTotalCount(dataType, filters));

        return preview;
    }

    /**
     * 估算导出文件大小
     *
     * @param dataType 数据类型
     * @param filters  过滤条件
     * @return 估算文件大小（字节）
     */
    @Override
    public long estimateExportFileSize(String dataType, Map<String, Object> filters) {
        log.info("估算导出文件大小: dataType={}", dataType);

        long totalCount = getTotalCount(dataType, filters);
        long avgRecordSize = getAverageRecordSize(dataType);

        return totalCount * avgRecordSize;
    }

    /**
     * 清理过期导出文件
     *
     * @param days 过期天数
     * @return 清理的文件数量
     */
    @Override
    @Transactional
    public int cleanupExpiredExportFiles(int days) {
        log.info("清理过期导出文件: days={}", days);

        LocalDateTime expireDate = LocalDateTime.now().minusDays(days);
        List<ExportTask> expiredTasks = exportTaskRepository.findByCreatedAtBeforeAndStatus(expireDate, "COMPLETED");

        int cleanedCount = 0;
        for (ExportTask task : expiredTasks) {
            if (task.getFilePath() != null) {
                deleteExportFile(task.getFilePath());
                task.setFilePath(null);
                task.setStatus("EXPIRED");
                exportTaskRepository.save(task);
                cleanedCount++;
            }
        }

        return cleanedCount;
    }

    /**
     * 获取导出任务统计
     *
     * @param userId 用户ID
     * @return 导出任务统计
     */
    @Override
    public Map<String, Object> getExportTaskStatistics(Long userId) {
        log.info("获取导出任务统计: userId={}", userId);

        Map<String, Object> statistics = new HashMap<>();

        if (userId != null) {
            statistics.put("totalTasks", exportTaskRepository.countByUserId(userId));
            statistics.put("completedTasks", exportTaskRepository.countByUserIdAndStatus(userId, "COMPLETED"));
            statistics.put("pendingTasks", exportTaskRepository.countByUserIdAndStatus(userId, "PENDING"));
            statistics.put("failedTasks", exportTaskRepository.countByUserIdAndStatus(userId, "FAILED"));
            statistics.put("totalDownloads", exportTaskRepository.sumDownloadCountByUserId(userId));
        } else {
            statistics.put("totalTasks", exportTaskRepository.countTotal());
            statistics.put("completedTasks", exportTaskRepository.countByStatus("COMPLETED"));
            statistics.put("pendingTasks", exportTaskRepository.countByStatus("PENDING"));
            statistics.put("failedTasks", exportTaskRepository.countByStatus("FAILED"));
            statistics.put("totalDownloads", exportTaskRepository.sumTotalDownloadCount());
        }

        return statistics;
    }

    /**
     * 重试导出任务
     *
     * @param taskId 任务ID
     */
    @Override
    @Transactional
    public void retryExportTask(Long taskId) {
        log.info("重试导出任务: taskId={}", taskId);

        ExportTask task = getExportTask(taskId);

        if (!"FAILED".equals(task.getStatus())) {
            throw new RuntimeException("只能重试失败的任务");
        }

        task.setStatus("PENDING");
        task.setProgress(0);
        task.setErrorMessage(null);
        task.setUpdatedAt(LocalDateTime.now());
        exportTaskRepository.save(task);

        // 异步执行导出任务
        executeExportTaskAsync(taskId);
    }

    /**
     * 设置导出任务优先级
     *
     * @param taskId   任务ID
     * @param priority 优先级
     */
    @Override
    @Transactional
    public void setExportTaskPriority(Long taskId, int priority) {
        log.info("设置导出任务优先级: taskId={}, priority={}", taskId, priority);

        ExportTask task = getExportTask(taskId);
        task.setPriority(priority);
        task.setUpdatedAt(LocalDateTime.now());
        exportTaskRepository.save(task);
    }

    /**
     * 获取导出任务进度
     *
     * @param taskId 任务ID
     * @return 任务进度
     */
    @Override
    public Map<String, Object> getExportTaskProgress(Long taskId) {
        log.info("获取导出任务进度: taskId={}", taskId);

        ExportTask task = getExportTask(taskId);

        Map<String, Object> progress = new HashMap<>();
        progress.put("taskId", taskId);
        progress.put("status", task.getStatus());
        progress.put("progress", task.getProgress());
        progress.put("estimatedSize", task.getEstimatedSize());
        progress.put("actualSize", task.getActualSize());
        progress.put("startedAt", task.getStartedAt());
        progress.put("completedAt", task.getCompletedAt());
        progress.put("errorMessage", task.getErrorMessage());

        return progress;
    }

    /**
     * 暂停导出任务
     *
     * @param taskId 任务ID
     */
    @Override
    @Transactional
    public void pauseExportTask(Long taskId) {
        log.info("暂停导出任务: taskId={}", taskId);

        ExportTask task = getExportTask(taskId);

        if (!"PROCESSING".equals(task.getStatus())) {
            throw new RuntimeException("只能暂停正在处理的任务");
        }

        task.setStatus("PAUSED");
        task.setUpdatedAt(LocalDateTime.now());
        exportTaskRepository.save(task);
    }

    /**
     * 恢复导出任务
     *
     * @param taskId 任务ID
     */
    @Override
    @Transactional
    public void resumeExportTask(Long taskId) {
        log.info("恢复导出任务: taskId={}", taskId);

        ExportTask task = getExportTask(taskId);

        if (!"PAUSED".equals(task.getStatus())) {
            throw new RuntimeException("只能恢复已暂停的任务");
        }

        task.setStatus("PROCESSING");
        task.setUpdatedAt(LocalDateTime.now());
        exportTaskRepository.save(task);

        // 异步继续执行导出任务
        executeExportTaskAsync(taskId);
    }

    /**
     * 批量删除导出任务
     *
     * @param taskIds 任务ID列表
     */
    @Override
    @Transactional
    public void batchDeleteExportTasks(List<Long> taskIds) {
        log.info("批量删除导出任务: taskIds={}", taskIds);

        for (Long taskId : taskIds) {
            deleteExportTask(taskId);
        }
    }

    /**
     * 获取导出配额使用情况
     *
     * @param userId 用户ID
     * @return 配额使用情况
     */
    @Override
    public Map<String, Object> getExportQuotaUsage(Long userId) {
        log.info("获取导出配额使用情况: userId={}", userId);

        Map<String, Object> quotaUsage = new HashMap<>();

        // 今日导出次数
        LocalDateTime todayStart = LocalDateTime.now().toLocalDate().atStartOfDay();
        LocalDateTime todayEnd = todayStart.plusDays(1);
        long todayExports = exportTaskRepository.countByUserIdAndCreatedAtBetween(userId, todayStart, todayEnd);

        // 本月导出次数
        LocalDateTime monthStart = LocalDateTime.now().withDayOfMonth(1).toLocalDate().atStartOfDay();
        long monthlyExports = exportTaskRepository.countByUserIdAndCreatedAtAfter(userId, monthStart);

        quotaUsage.put("dailyUsed", todayExports);
        quotaUsage.put("dailyLimit", 10); // 假设每日限制10次
        quotaUsage.put("monthlyUsed", monthlyExports);
        quotaUsage.put("monthlyLimit", 100); // 假设每月限制100次

        return quotaUsage;
    }

    // 私有辅助方法

    private void executeExportTaskAsync(Long taskId) {
        CompletableFuture.runAsync(() -> {
            try {
                executeExportTask(taskId);
            } catch (Exception e) {
                log.error("导出任务执行失败: taskId={}", taskId, e);
                updateTaskStatus(taskId, "FAILED", e.getMessage());
            }
        });
    }

    private void executeExportTask(Long taskId) {
        log.info("开始执行导出任务: taskId={}", taskId);

        ExportTask task = getExportTask(taskId);

        // 更新任务状态为处理中
        updateTaskStatus(taskId, "PROCESSING", null);
        task.setStartedAt(LocalDateTime.now());
        exportTaskRepository.save(task);

        try {
            // 模拟导出过程
            for (int i = 0; i <= 100; i += 10) {
                Thread.sleep(500); // 模拟处理时间
                updateTaskProgress(taskId, i);
            }

            // 生成导出文件路径
            String filePath = generateExportFilePath(task);

            // 更新任务完成状态
            task.setStatus("COMPLETED");
            task.setProgress(100);
            task.setFilePath(filePath);
            task.setActualSize(estimateExportFileSize(task.getDataType(), parseFilters(task.getFilters())));
            task.setCompletedAt(LocalDateTime.now());
            task.setUpdatedAt(LocalDateTime.now());
            exportTaskRepository.save(task);

            log.info("导出任务完成: taskId={}, filePath={}", taskId, filePath);

        } catch (Exception e) {
            log.error("导出任务执行失败: taskId={}", taskId, e);
            updateTaskStatus(taskId, "FAILED", e.getMessage());
        }
    }

    private void updateTaskStatus(Long taskId, String status, String errorMessage) {
        ExportTask task = getExportTask(taskId);
        task.setStatus(status);
        task.setErrorMessage(errorMessage);
        task.setUpdatedAt(LocalDateTime.now());
        exportTaskRepository.save(task);
    }

    private void updateTaskProgress(Long taskId, int progress) {
        ExportTask task = getExportTask(taskId);
        task.setProgress(progress);
        task.setUpdatedAt(LocalDateTime.now());
        exportTaskRepository.save(task);
    }

    private String generateExportFilePath(ExportTask task) {
        String fileName = String.format("%s_%s_%d.%s",
                task.getDataType().toLowerCase(),
                task.getCreatedAt().toLocalDate().toString(),
                task.getId(),
                task.getFormat().toLowerCase());
        return "/exports/" + fileName;
    }

    private String generateDownloadUrl(String filePath) {
        // 生成临时下载链接，包含过期时间等安全措施
        return "/api/export/download?file=" + filePath + "&token=" + UUID.randomUUID().toString();
    }

    private void deleteExportFile(String filePath) {
        // TODO: 实现文件删除逻辑
        log.info("删除导出文件: {}", filePath);
    }

    private Map<String, Object> createTemplate(String name, String description, List<String> fields) {
        Map<String, Object> template = new HashMap<>();
        template.put("name", name);
        template.put("description", description);
        template.put("fields", fields);
        return template;
    }

    private List<Map<String, Object>> getPreviewData(String dataType, Map<String, Object> filters, int limit) {
        // TODO: 根据数据类型和过滤条件获取预览数据
        List<Map<String, Object>> previewData = new ArrayList<>();

        for (int i = 0; i < Math.min(limit, 5); i++) {
            Map<String, Object> record = new HashMap<>();
            record.put("id", i + 1);
            record.put("name", "示例数据 " + (i + 1));
            record.put("createdAt", LocalDateTime.now().minusDays(i));
            previewData.add(record);
        }

        return previewData;
    }

    private long getTotalCount(String dataType, Map<String, Object> filters) {
        // TODO: 根据数据类型和过滤条件获取总数量
        switch (dataType.toUpperCase()) {
            case "MATERIAL":
                return materialRepository.countTotal();
            case "COPYWRITING":
                return copywritingRepository.countTotal();
            case "TAG":
                return tagRepository.countTotal();
            default:
                return 0;
        }
    }

    private long getAverageRecordSize(String dataType) {
        // TODO: 根据数据类型返回平均记录大小
        switch (dataType.toUpperCase()) {
            case "MATERIAL":
                return 1024; // 1KB
            case "COPYWRITING":
                return 512; // 512B
            case "TAG":
                return 256; // 256B
            default:
                return 512;
        }
    }

    private Map<String, Object> parseFilters(String filtersStr) {
        // TODO: 解析过滤条件字符串
        return new HashMap<>();
    }
}